﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;

namespace Xodeuz.SP.Common
{
    public class BatchXmlCreator
    {
        private const string XMLSTART = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>";
        private const string BATCH_CONTAINER = "<Batch>{0}</Batch>";
        private const string METHOD_DELETE = "<Method><SetList Scope=\"Request\">{1}</SetList><SetVar Name=\"ID\">{0}</SetVar><SetVar Name=\"Cmd\">Delete</SetVar></Method>";
        private const string OWS_BATCH_CONTAINER = "<ows:Batch OnError=\"Return\">{0}</ows:Batch>";
        private const string METHOD_CREATE = "<Method ID=\"{0}\"><SetList>{1}</SetList><SetVar Name=\"Cmd\">Save</SetVar><SetVar Name=\"ID\">New</SetVar>{2}</Method>";
        private const string METHOD_UPDATE = "<Method ID=\"{0}\"><SetList>{1}</SetList><SetVar Name=\"Cmd\">Save</SetVar><SetVar Name=\"ID\">{3}</SetVar>{2}</Method>";
        private const string SET_VAR_FORMAT = "<SetVar Name=\"urn:schemas-microsoft-com:office:office#{0}\">{1}</SetVar>";
 
        public static string CreateDeletionXml(List<int> collection, Guid listId)
        {
            var methodBuilder = new StringBuilder();
            foreach (var itemId in collection)
            {
                methodBuilder.Append(string.Format(METHOD_DELETE, itemId, listId));
            }
            return XMLSTART + String.Format(BATCH_CONTAINER, methodBuilder);
        }

        public static List<String> CreateItemsXml<T>(List<T> items, Guid listId)
        {
            List<String> batches = new List<string>();
            int maxBatch = 2000;
            int currentRow = 0;

            Type type = typeof (T);
            var names = ReflectionService.GetPropertyNameWithCustomAttribute<Field>(type);
            var props = ReflectionService.PublicPropertyInfos(type);
            var batchBuilder = new StringBuilder();

            foreach (T item in items)
            {
                if (currentRow == maxBatch)
                {
                    batches.Add(XMLSTART + String.Format(OWS_BATCH_CONTAINER, batchBuilder));
                    batchBuilder = new StringBuilder();
                    currentRow = 0;
                }
                var methodBuilder = new StringBuilder();
                
                foreach (PropertyInfo propertyInfo in props)
                {
                    if (names.ContainsKey(propertyInfo.Name))
                    {
                        var fieldName = names[propertyInfo.Name];

                        if(ReadOnly.Fields.Contains(fieldName.InternalName)) continue;
                        
                        var value = propertyInfo.GetValue(item, null);

                        if (value != null)
                        {
                            methodBuilder.AppendFormat(SET_VAR_FORMAT, fieldName.InternalName, value);
                        }
                    }
                }
                batchBuilder.Append(string.Format(METHOD_CREATE, items.IndexOf(item), listId, methodBuilder));
                currentRow++;
            }

            batches.Add(XMLSTART + String.Format(OWS_BATCH_CONTAINER, batchBuilder));

            return batches;
        }

        public static List<String> UpdateItemsXml<T>(List<T> items, Guid listId)
        {
            List<String> batches = new List<string>();
            int maxBatch = 2000;
            int currentRow = 0;

            Type type = typeof(T);
            var names = ReflectionService.GetPropertyNameWithCustomAttribute<Field>(type);
            var props = ReflectionService.PublicPropertyInfos(type);
            var batchBuilder = new StringBuilder();

            var identityProperty = ReflectionService.GetPropertyInfoByName(type, "ItemId");

            foreach (T item in items)
            {
                if (currentRow == maxBatch)
                {
                    batches.Add(XMLSTART + String.Format(OWS_BATCH_CONTAINER, batchBuilder));
                    batchBuilder = new StringBuilder();
                    currentRow = 0;
                }
                var methodBuilder = new StringBuilder();

                foreach (PropertyInfo propertyInfo in props)
                {
                    if (names.ContainsKey(propertyInfo.Name))
                    {
                        var fieldName = names[propertyInfo.Name];

                        if (ReadOnly.Fields.Contains(fieldName.InternalName)) continue;

                        var value = propertyInfo.GetValue(item, null);

                        if (value != null)
                        {
                            methodBuilder.AppendFormat(SET_VAR_FORMAT, fieldName.InternalName, value);
                        }
                    }
                }

                string id = identityProperty.GetValue(item, null).ToStringSafe();
                batchBuilder.Append(string.Format(METHOD_UPDATE, items.IndexOf(item), listId, methodBuilder, id));
                currentRow++;
            }

            batches.Add(XMLSTART + String.Format(OWS_BATCH_CONTAINER, batchBuilder));

            return batches;
        }
    }
}
